//
//  HQLocationManager.m
//  o_amap
//
//  Created by Q神 on 2021/4/6.
//

#import "HQLocationManager.h"
/// 定位
#import <AMapFoundationKit/AMapFoundationKit.h>
#import <AMapLocationKit/AMapLocationKit.h>

#import "GdMapFlutterStreamManager.h"
#import "HQMapTools.h"

#import "MJExtension.h"
#import "LocationClientOptionsModel.h"
#import "LocationResultModel.h"
#import "LatLngModel.h"
#import "LocationCalculateDistanceOptionsModel.h"
#import "LocationTransformationOptionsModel.h"

@interface HQLocationManager() <AMapLocationManagerDelegate>

@property (nonatomic, strong) AMapLocationManager * locationManager;

@property (nonatomic, strong) HQMapTools * mapTools;
@property (nonatomic, strong) GdMapFlutterStreamHandler *streamHandler;

/// 倒计时
@property (nonatomic, assign) NSInteger interval;
@property (nonatomic, assign) BOOL isOnceLocation;
@property (nonatomic, strong) NSTimer *timer;

@end

@implementation HQLocationManager

+ (instancetype)shareInstance {
    static dispatch_once_t onceToken;
    static HQLocationManager * manager = nil;
    dispatch_once(&onceToken, ^{
        manager = [[HQLocationManager alloc] init];
    });
    return manager;
}

#pragma mark -- 插件方法

- (void)locationWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar withMapPlugin:(NSObject<FlutterPlugin> * _Nonnull)mapPlugin streamHandler:(GdMapFlutterStreamHandler * _Nullable)handler {
    
    self.streamHandler = handler;

    FlutterMethodChannel *locationChannel = [FlutterMethodChannel methodChannelWithName:@"com.p595263720.zit/location" binaryMessenger:[registrar messenger]];
    [registrar addMethodCallDelegate:mapPlugin channel:locationChannel];
    FlutterEventChannel *locationReceiveChannel = [FlutterEventChannel eventChannelWithName:@"com.p595263720.zit/location_receive" binaryMessenger:[registrar messenger]];
    [locationReceiveChannel setStreamHandler:handler];
}

- (void)locationMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result {

    if([@"startLocation" isEqualToString:call.method]) {
        /// 开始定位
        if ([[call.arguments allKeys] containsObject:@"options"]) {
            NSDictionary *args = [self.mapTools parseJSONStringToNSDictionary: call.arguments[@"options"]];
            LocationClientOptionsModel *optionsModel = [LocationClientOptionsModel mj_objectWithKeyValues:args];
            if ([optionsModel initWithOptionsForLocationManager:self.locationManager]) {
                self.interval = optionsModel.interval;
                self.isOnceLocation = optionsModel.isOnceLocation;
                [self startLocation:result];
            }
        }
        NSLog(@"%d, %ld, == %@", self.isOnceLocation, (long)self.interval, call.arguments);

    } else if([@"stopLocation" isEqualToString:call.method]) {
        /// 停止定位
        [self stopLocation];
        result(@YES);

    } else if([@"destroyLocation" isEqualToString:call.method]) {
        /// 当不实用定位时，销毁定位, 开始时重新创建定位类
        [self destroyLocation];
        result(@YES);

    } else if([@"coordinateTransformation" isEqualToString:call.method]) {
        /// 坐标转换 实现各种类型坐标转换成高德坐标   coordinateType 坐标类型参数本类常量
        [self coordinateTransformation:call result: result];

    } else if([@"calculateLineDistance" isEqualToString:call.method]) {
        /// 计算两点间距离 单位 米
        [self calculateLineDistance:call result: result];

    }
}

#pragma mark -- 事件处理

/**
 启动定位
 */
- (void)startLocation:(FlutterResult)result {
    self.flutterResult = result;
    [self.locationManager setLocatingWithReGeocode:YES];
    [self.locationManager startUpdatingLocation];
}

/**
 停止定位
 */
- (void)stopLocation {
    self.flutterResult = nil;
    [self.locationManager stopUpdatingLocation];
    [self.timer invalidate];
    self.timer = nil;
}

/**
 当不实用定位时，销毁定位, 开始时重新创建定位类
 */
- (void)destroyLocation {
    [self.locationManager stopUpdatingLocation];
    [self.locationManager setDelegate:nil];
}

/**
 计算两点间距离 单位 米
 */
- (void)calculateLineDistance:(FlutterMethodCall *)call result:(FlutterResult)result {
    if (call.arguments) {
        LocationCalculateDistanceOptionsModel *model = [LocationCalculateDistanceOptionsModel mj_objectWithKeyValues:call.arguments];
        result([NSNumber numberWithDouble:[model calculateLineDistance]]);
    }
}

/**
 坐标转换 实现各种类型坐标转换成高德坐标   coordinateType 坐标类型参数本类常量
 */
- (void)coordinateTransformation:(FlutterMethodCall *)call result:(FlutterResult)result {
    if (call.arguments) {
        LocationTransformationOptionsModel *model = [LocationTransformationOptionsModel mj_objectWithKeyValues:call.arguments];
        result([self.mapTools hq_jsonStringCompactFormatForDictionary:[[model coordinateTransformation] mj_keyValues]]);
    }
}

#pragma mark -- 定位

/**
 *  @brief 连续定位回调函数
 *  @param manager 定位 BMKLocationManager 类。
 *  @param location 定位结果。
 *  自 V2.2.0 版本起amapLocationManager:didUpdateLocation:reGeocode:方法可以在回调位置的同时回调逆地理编码信息。请注意，如果实现了amapLocationManager:didUpdateLocation:reGeocode: 回调，将不会再回调amapLocationManager:didUpdateLocation: 方法。
 */
- (void)amapLocationManager:(AMapLocationManager *)manager didUpdateLocation:(CLLocation *)location reGeocode:(AMapLocationReGeocode *)reGeocode {

    NSLog(@"location:{lat:%f; lon:%f; accuracy:%f}", location.coordinate.latitude, location.coordinate.longitude, location.horizontalAccuracy);
    if (self.timer == nil) {
        self.timer = [NSTimer scheduledTimerWithTimeInterval:(self.interval / 1000) target:self selector:@selector(printCurrentTime:) userInfo:nil repeats:YES];
        /// 定位结果回调时间
        LocationResultModel *resultModel = [LocationResultModel initWithLocation:location reGeocode:reGeocode];
        resultModel.callbackTime = [self.mapTools getFormatTime:[NSDate date]];
        NSString *jsonString = [self.mapTools hq_jsonStringPrettyPrintedFormatForDictionary:[resultModel mj_keyValues]];
        self.streamHandler.eventSink(jsonString);
    }
}

- (void)printCurrentTime:(id)sender {
    NSLog(@"5分钟到了=======上传位置");
    [self.timer invalidate];
    [self.locationManager stopUpdatingLocation];
    if (!self.isOnceLocation) {
        self.timer = nil;
        [self.locationManager startUpdatingLocation];
    }
}

/**
 *  @brief 当定位发生错误时，会调用代理的此方法。
 *  @param manager 定位 AMapLocationManager 类。
 *  @param error 返回的错误，参考 CLError 。
 */
- (void)amapLocationManager:(AMapLocationManager *)manager didFailWithError:(NSError *)error {
    
    /// 定位结果回调时间
    LocationResultModel *resultModel = [LocationResultModel initWithLocation:nil reGeocode:nil];
    resultModel.callbackTime = [self.mapTools getFormatTime:[NSDate date]];
    NSString *jsonString = [self.mapTools hq_jsonStringPrettyPrintedFormatForDictionary:[resultModel mj_keyValues]];
    self.streamHandler.eventSink(jsonString);
}

/**
 要在iOS 11及以上版本使用后台定位服务, 需要实现amapLocationManager:doRequireLocationAuth: 代理方法
 当plist配置NSLocationAlwaysUsageDescription或者NSLocationAlwaysAndWhenInUseUsageDescription，并且[CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined，会调用代理的此方法。
      此方法实现调用申请后台权限API即可：[locationManager requestAlwaysAuthorization](必须调用,不然无法正常获取定位权限)
 */
- (void)amapLocationManager:(AMapLocationManager *)manager doRequireLocationAuth:(CLLocationManager *)locationManager {
    [locationManager requestAlwaysAuthorization];
}

#pragma mark -- 懒加载

- (AMapLocationManager *)locationManager {
    if (!_locationManager) {
        _locationManager = [[AMapLocationManager alloc] init];
        _locationManager.delegate = self;
    }
    return _locationManager;
}

- (HQMapTools *)mapTools {
    if (!_mapTools) {
        _mapTools = [HQMapTools shareInstance];
    }
    return _mapTools;
}

@end
